package com.budwk.app.sqfwDoc.codeGeneratorV2.pdfService;

import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.budwk.app.jim.SqfwWebSocket;
import com.budwk.app.jim.WebSocketMsgDTO;
import com.budwk.app.sqfw.constants.SqfwWebSocketMsgConstants;
import com.budwk.app.sqfw.dto.SqfwCompleteFlowUpdateDTO;
import com.budwk.app.sqfw.enums.SqfwFormSummaryFieldEnum;
import com.budwk.app.sqfw.models.Sqfw_completeflow;
import com.budwk.app.sqfw.models.Sqfw_formSummary_new;
import com.budwk.app.sqfw.services.SqfwCompleteflowService;
import com.budwk.app.sqfw.services.SqfwFormsummaryNewService;
import com.budwk.app.sqfw.services.SqfwWorkorderService;
import com.budwk.app.sqfw.services.datamange.DataMangeCommunityService;
import com.budwk.app.sqfwDoc.codeGeneratorV2.capacity.AbstractCreatePdfCapacity;
import com.budwk.app.sqfwDoc.codeGeneratorV2.capacity.IAfterCreatePdfCapacity;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.CommonParam;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.CompleteFlowBusinessParam;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.CompleteFlowPdfParamForController;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.PdfGenerateParam;
import com.budwk.app.sqfwDoc.codeGeneratorV2.generate.BasePdfGenerator;
import com.budwk.app.sqfwDoc.codeGeneratorV2.generate.ResultOfPdfGenerator;
import com.budwk.app.sqfwDoc.codeGeneratorV2.result.GeneratorPdfWordResult;
import com.budwk.app.sqfwDoc.dto.CompleteFlowTemplateCodeUpdateDTO;
import com.budwk.app.sys.models.Sys_unit;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.services.SysUnitService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.util.StrUtil;
import com.budwk.app.util.ThreadPoolExecutorUtil;
import com.budwk.app.util.poiUtils.CommonPdfAndWordResult;
import com.budwk.app.util.poiUtils.nutzBeanUtils.NutzIocUtils;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.trans.Trans;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author ZY.Wang
 * @since 2024/1/24
 */
@Slf4j
public abstract class CompleteFlowCommonPdfService extends AbstractCreatePdfCapacity implements IAfterCreatePdfCapacity {

    private final String completeFlowConsName = "completeFlow";
    private final String forSummaryNewConsName = "formSummaryNew";

    ExecutorService executorService = Executors.newFixedThreadPool(50);

    @Inject
    private DataMangeCommunityService dataMangeCommunityService;

    /**
     * 异步生成pdf然后通过websocket通知前端
     *
     * @param paramForController 创建pdf所提供的参数
     */
    public void createPdfAndMsg(CompleteFlowPdfParamForController paramForController) {

        // 存储业务数据
        Map<String, Object> businessDataMap = saveBusinessData(paramForController);

        // 创建pdf，并在pdf之后发送socket消息通知前端
        executorService.execute(() -> {

            // 初始化一下生成结果
            GeneratorPdfWordResult generateResult = new GeneratorPdfWordResult();

            Sqfw_completeflow completeFlow = (Sqfw_completeflow) businessDataMap.get(completeFlowConsName);
            Sqfw_formSummary_new formSummaryNew = (Sqfw_formSummary_new) businessDataMap.get(forSummaryNewConsName);

            try {
                PdfGenerateParam pdfGenerateParam = getPdfGenerateParamFromBusinessData(completeFlow, formSummaryNew, businessDataMap);
                pdfGenerateParam.setPdfCreateConfigList(paramForController.getPdfCreateConfigList());

                generateResult = super.generatePdf(pdfGenerateParam);

            } catch (Exception e) {
                log.info("pdf create error,will update completeFlow status");
            }

            generateResult.getBridgeMap().putAll(businessDataMap);
            generateResult.getBridgeMap().put("userId", paramForController.getUserId());
            generateResult.setReCreatePdfFlag(false);
            afterGeneratePdf(generateResult);
        });
    }

    /**
     * 重新创建pdf并发送消息
     *
     * @param paramForController 参数数据
     */
    public void reCreatePdfAndMsg(CompleteFlowPdfParamForController paramForController) {

        SqfwCompleteflowService sqfwCompleteflowService = NutzIocUtils.getBean(SqfwCompleteflowService.class);
        SqfwFormsummaryNewService sqfwFormsummaryNewService = NutzIocUtils.getBean(SqfwFormsummaryNewService.class);

        String completeFlowId = paramForController.getCompleteFlowId();
        String userId = paramForController.getUserId();

        Sqfw_completeflow completeFlow = sqfwCompleteflowService.fetch(completeFlowId);
        if (completeFlow == null) return;

        Cnd cnd = Cnd.NEW();
        cnd.and(Sqfw_formSummary_new::getSqfwFlowId, "=", completeFlowId);
        Sqfw_formSummary_new formSummaryNew = sqfwFormsummaryNewService.fetch(cnd);
        if (formSummaryNew == null) return;

        Map<String, Object> businessDataMap = Maps.newHashMap();

        beforeReGenPdf(completeFlow, formSummaryNew, businessDataMap);

        // 创建pdf，并在pdf之后发送socket消息通知前端
        executorService.execute(() -> {
            PdfGenerateParam pdfGenerateParam = getPdfGenerateParamFromBusinessData(completeFlow, formSummaryNew, businessDataMap);
            GeneratorPdfWordResult generateResult = super.generatePdf(pdfGenerateParam);

            // 设置需要向下传递的数据
            Map<String, Object> bridgeMap = generateResult.getBridgeMap();
            if (bridgeMap == null) {
                bridgeMap = Maps.newHashMap();
            }

            bridgeMap.put("completeFlow", completeFlow);
            bridgeMap.put("formSummaryNew", formSummaryNew);
            bridgeMap.put("userId", userId);
            generateResult.setBridgeMap(bridgeMap);

            generateResult.setReCreatePdfFlag(true);

            afterGeneratePdf(generateResult);
        });
    }


    /**
     * 同步生成pdf
     *
     * @param paramForController 创建pdf所提供的数据
     * @return 生成pdf结果
     */
    public GeneratorPdfWordResult createPdfSync(CompleteFlowPdfParamForController paramForController) {

        Map<String, Object> businessDataMap = saveBusinessData(paramForController);
        Sqfw_completeflow completeFlow = (Sqfw_completeflow) businessDataMap.get("sqfwCompleteFlow");
        Sqfw_formSummary_new formSummaryNew = (Sqfw_formSummary_new) businessDataMap.get("formSummaryNew");
        PdfGenerateParam pdfGenerateParam = getPdfGenerateParamFromBusinessData(completeFlow, formSummaryNew, Maps.newHashMap());
        return super.generatePdf(pdfGenerateParam);
    }

    /**
     * 从业务数据中创建生成pdf所需要的参数
     *
     * @param completeFlow    工作流
     * @param formSummaryNew  表单
     * @param businessDataMap 自定义想要返回的参数
     * @return 结果
     */
    public PdfGenerateParam getPdfGenerateParamFromBusinessData(Sqfw_completeflow completeFlow, Sqfw_formSummary_new formSummaryNew, Map<String, Object> businessDataMap) {

        PdfGenerateParam pdfGenerateParam = new PdfGenerateParam();

        pdfGenerateParam.setAbstractCustomerPdfCreateField(getCustomerPdfField(formSummaryNew.getParamData()));

        CompleteFlowBusinessParam businessParam = new CompleteFlowBusinessParam();
        businessParam.setCompleteFlow(completeFlow);
        businessParam.setFormSummary(formSummaryNew);
        businessParam.setCompleteFlowId(completeFlow.getId());
        businessParam.setFillDate(formSummaryNew.getFillDate());
        pdfGenerateParam.setBusinessParam(businessParam);
        CommonParam commonParam = getCreateUserPdfParam(formSummaryNew.getCreateBy());

        pdfGenerateParam.setCreateUserCommonParam(commonParam);

        customerPopularPdfGenerateParam(pdfGenerateParam, businessDataMap);

        return pdfGenerateParam;
    }

    /**
     * 存储业务数据
     *
     * @param paramForController 创建pdf时controller提供的数据
     * @return 结果
     */
    public Map<String, Object> saveBusinessData(CompleteFlowPdfParamForController paramForController) {

        String userId = paramForController.getUserId();

        Map<String, Object> callBackMap = Maps.newHashMap();
        List<String> ids = new ArrayList<String>();
        Trans.exec(() -> {

            CompleteFlowTemplateCodeUpdateDTO formSummaryWithFlow = paramForController.getCompleteFlowDataDTO();

            SysUserService sysUserService = NutzIocUtils.getBean(SysUserService.class);
            SqfwCompleteflowService sqfwCompleteflowService = NutzIocUtils.getBean(SqfwCompleteflowService.class);
            SqfwWorkorderService sqfwWorkorderService = NutzIocUtils.getBean(SqfwWorkorderService.class);
            SqfwFormsummaryNewService sqfwFormsummaryNewService = NutzIocUtils.getBean(SqfwFormsummaryNewService.class);

            Sys_user sysUser = sysUserService.fetch(userId);

            Sqfw_formSummary_new formSummary = formSummaryWithFlow.getFormSummary();
            if (StringUtils.isEmpty(formSummary.getType())) {
                formSummary.setType(getSummaryType());
            }
            // 首先现需要生成一个工作流信息
            SqfwCompleteFlowUpdateDTO completeFlow = formSummaryWithFlow.getCompleteFlow();
            if (completeFlow == null) {
                completeFlow = new SqfwCompleteFlowUpdateDTO();
                completeFlow.setFileType(formSummary.getType());
                completeFlow.setLatestFlowRemark("完成了文档");
                completeFlow.setTitle("完成了文档");
                completeFlow.setSqfwId(StrUtil.getUUID());

                completeFlow.setSqfwId(StringUtils.isNotEmpty(formSummary.getSqfwId()) ? formSummary.getSqfwId() : StrUtil.getUUID());
            }
            completeFlow.setUserId(sysUser.getId());
            completeFlow.setUserName(sysUser.getUsername());
            completeFlow.setResourcePath("creating");
            completeFlow.setCreateDate(new Date());

            beforeInsertCompleteFlow(completeFlow);
            sqfwCompleteflowService.insert(completeFlow);
            afterInsertCompleteFlow(completeFlow);

            // 更新工单表中的最新工作流备注
            sqfwWorkorderService.updateLatestFlowRemarkWithCompleteFlow(completeFlow.getWorkerId(), completeFlow.getFileType(), false);

            formSummary.setParamData(formSummary.getParamData());
            formSummary.setCreateDate(new Date());
            formSummary.setCreateBy(userId);
            formSummary.setSqfwFlowId(completeFlow.getId());
            formSummary.setSqfwId(StringUtils.isNotEmpty(formSummary.getSqfwId()) ? formSummary.getSqfwId() :completeFlow.getSqfwId());
            formSummary.setWorkOrderId(StringUtils.isNotEmpty(formSummary.getWorkOrderId()) ? formSummary.getWorkOrderId() :completeFlow.getWorkerId());
            formSummary.setCreateUserName(sysUser.getUsername());
            formSummary.setCreateUserPhone(sysUser.getLoginname());
            formSummary.setUpdateBy(sysUser.getId());
            formSummary.setUpdateDate(new Date());
            formSummary.setUpdateUserName(sysUser.getUsername());
            formSummary.setUpdateUserPhone(sysUser.getLoginname());
            formSummary.setProvince(sysUser.getProvince());
            formSummary.setCity(sysUser.getCity());
            formSummary.setCounty(sysUser.getCounty());
            formSummary.setDistrict(sysUser.getDistrict());
            formSummary.setCommunity(sysUser.getCommunity());
            formSummary.setCheckStatus(SqfwFormSummaryFieldEnum.check_status_init.getCode());
            formSummary.setUnitName(sysUser.getUnitName());
            formSummary.setUnitId(sysUser.getUnitId());

            if (formSummary.getFillDate() == null) {
                formSummary.setFillDate(new Date());
            }

            beforeInsertForSummary(formSummary);
            sqfwFormsummaryNewService.insert(formSummary);
            afterInsertForSummary(formSummary);

            callBackMap.put(completeFlowConsName, completeFlow);
            callBackMap.put(forSummaryNewConsName, formSummary);
            ids.add(formSummary.getId());
        });
        // 异步解析入数据管理模块
        try {
            ExecutorService executorService = ThreadPoolExecutorUtil.getInstance();
            CompletableFuture.runAsync(() -> {
                dataMangeCommunityService.cleanDataBySummaryId(ids);
            }, executorService);
        } catch (Exception ex) {
            log.error("clean data service error! id : {}", JSONUtil.toJsonStr(ids));
        }
        return callBackMap;
    }

    @Override
    public void afterGeneratePdf(GeneratorPdfWordResult generateResult) {

        Map<String, Object> bridgeMap = generateResult.getBridgeMap();
        Sqfw_completeflow completeFlow = (Sqfw_completeflow) bridgeMap.get(completeFlowConsName);

        SqfwCompleteflowService sqfwCompleteflowService = NutzIocUtils.getBean(SqfwCompleteflowService.class);

        CommonPdfAndWordResult pdfAndWordResult = generateResult.getPdfAndWordResult();
        if (StringUtils.isBlank(pdfAndWordResult.getPdfUrl()) || !generateResult.getCreateFlag()) {
            System.out.println("创建PDF失败");
            completeFlow.setResourcePath("error");
            completeFlow.setResourcePath("error");
            sqfwCompleteflowService.update(completeFlow);

            afterGeneratePdfError(generateResult);
        } else {

            SqfwWebSocket sqfwWebSocket = NutzIocUtils.getBean(SqfwWebSocket.class);
            String userId = (String) bridgeMap.get("userId");

            completeFlow.setResourcePath(pdfAndWordResult.getPdfUrl());
            sqfwCompleteflowService.update(completeFlow);

            // 发送一个websocket通知前端
            WebSocketMsgDTO msgDTO = new WebSocketMsgDTO();
            msgDTO.setType(getPdfCreateSocketType());
            msgDTO.setMsg("PDF生成成功");
            sqfwWebSocket.sendMessage(userId, msgDTO);

            afterGeneratePdfSuccess(generateResult);
        }
    }


    //-----------------------------------------------------------------------------
    //  一些可以重写的方法
    //-----------------------------------------------------------------------------

    /**
     * 根据用户id创建通用参数
     *
     * @param createBy 用户id
     * @return 结果
     */
    protected CommonParam getCreateUserPdfParam(String createBy) {
        CommonParam commonParam = new CommonParam();
        SysUserService sysUserService = NutzIocUtils.getBean(SysUserService.class);
        Sys_user createUser = sysUserService.fetch(createBy);
        commonParam.setCreateUserId(createUser.getId());
        commonParam.setCreateUserName(createUser.getUsername());
        commonParam.setCreateUserPhone(createUser.getLoginname());
        commonParam.setUnitId(createUser.getUnitId());
        commonParam.setLevelCityUnitName(createUser.getUnitName());
        commonParam.setProvince(createUser.getProvince());
        commonParam.setCity(createUser.getCity());
        commonParam.setDistrict(createUser.getDistrict());
        commonParam.setCounty(createUser.getCounty());
        commonParam.setCommunity(createUser.getCommunity());
        commonParam.setCreateUserSigUrl(createUser.getSignatureUrl());

        SysUnitService sysUnitService = NutzIocUtils.getBean(SysUnitService.class);
        Sys_unit userUnit = sysUnitService.fetch(createUser.getUnitId());
        commonParam.setUnitName(userUnit.getName());
        return commonParam;
    }

    @Override
    public void popularPdfGenerateResultBridgeMap(GeneratorPdfWordResult result, List<ResultOfPdfGenerator> pdfResultList) {

    }

    protected void afterInsertForSummary(Sqfw_formSummary_new formSummary) {

    }

    protected void beforeInsertForSummary(Sqfw_formSummary_new formSummary) {

    }

    protected void afterInsertCompleteFlow(SqfwCompleteFlowUpdateDTO completeFlow) {

    }

    protected void beforeInsertCompleteFlow(SqfwCompleteFlowUpdateDTO completeFlow) {

    }

    /**
     * 当创建了pdf之后通知前端的时候发送socket消息类型
     * 请参照{@link SqfwWebSocketMsgConstants}
     *
     * @return 结果
     */
    protected String getPdfCreateSocketType() {
        return SqfwWebSocketMsgConstants.work_flow_pdf_created;
    }

    @Override
    protected void customerPopularPdfGenerateParam(PdfGenerateParam pdfGenerateParam, Map<String, Object> customerBusinessDataMap) {

    }

    /**
     * pdf创建失败，更新工作流之后自定义方法
     *
     * @param generateResult pdf创建结果
     */
    private void afterGeneratePdfError(GeneratorPdfWordResult generateResult) {

    }

    /**
     * pdf创建成功，更新工作流之后自定义方法
     *
     * @param generateResult 创建的结果
     */
    protected void afterGeneratePdfSuccess(GeneratorPdfWordResult generateResult) {

    }

    /**
     * 重新生成pdf之前可以自定义的操作
     *
     * @param completeFlow    工作流
     * @param formSummaryNew  表单数据
     * @param businessDataMap 需要进行传递到创建pdf的数据
     */
    protected void beforeReGenPdf(Sqfw_completeflow completeFlow, Sqfw_formSummary_new formSummaryNew, Map<String, Object> businessDataMap) {

    }

    /**
     * 允许可以在统一处理结果
     *
     * @param pdfResult pdf结果
     */
    protected void getPdfGenerateResultAfter(ResultOfPdfGenerator pdfResult, BasePdfGenerator generator) {

    }


    //-----------------------------------------------------------------------------
    //  抽象方法
    //-----------------------------------------------------------------------------

    @Override
    protected abstract void customerPopularPdfGenerateParam(PdfGenerateParam pdfGenerateParam);

    @Override
    protected abstract List<BasePdfGenerator> getPdfGenerator(PdfGenerateParam pdfGenerateParam);

    @Override
    protected abstract String getDownloadFileName(PdfGenerateParam pdfGenerateParam);

    protected abstract String getSummaryType();
}
